﻿using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class AssociationSwapperSpecification {
        [Test]
        public void ShouldSwapTwoCompositeTermsThatHaveSameName () {
            var i1 = new IntegerTerm (1);
            var i2 = new IntegerTerm (2);
            var i3 = new IntegerTerm (3);
            var i4 = new IntegerTerm (4);
            var i5 = new IntegerTerm (5);

            CompositeTerm outer = new CompositeTerm ("name");
            outer.Add ("first", i1, false);
            outer.Add ("middle", i2, false);

            CompositeTerm inner = new CompositeTerm ("name");
            outer.Add ("last", inner, false);

            inner.Add ("first", i3, false);
            inner.Add ("middle", i4, false);
            inner.Add ("last", i5, false);

            AssociationSwapper swapper = new AssociationSwapper ("first", "last");

            var result = swapper.Swap (outer);

            Assert.AreSame (inner, result);
            Assert.AreSame (outer, result.SubTerms ["first"]);
            Assert.AreSame (i1, outer.SubTerms ["first"]);
            Assert.AreSame (i2, outer.SubTerms ["middle"]);
            Assert.AreSame (i3, outer.SubTerms ["last"]);
            Assert.AreSame (i4, inner.SubTerms ["middle"]);
            Assert.AreSame (i5, inner.SubTerms ["last"]);
        }

        [Test]
        public void ShouldReturnOuterIfNamesDoNotMatch () {
            var i1 = new IntegerTerm (1);
            var i2 = new IntegerTerm (2);
            var i3 = new IntegerTerm (3);
            var i4 = new IntegerTerm (4);
            var i5 = new IntegerTerm (5);

            CompositeTerm outer = new CompositeTerm ("name1");
            outer.Add ("first", i1, false);
            outer.Add ("middle", i2, false);

            CompositeTerm inner = new CompositeTerm ("name2");
            outer.Add ("last", inner, false);

            inner.Add ("first", i3, false);
            inner.Add ("middle", i4, false);
            inner.Add ("last", i5, false);

            AssociationSwapper swapper = new AssociationSwapper ("first", "last");

            var result = swapper.Swap (outer);

            Assert.AreSame (outer, result);
            Assert.AreSame (i1, outer.SubTerms ["first"]);
            Assert.AreSame (i2, outer.SubTerms ["middle"]);
            Assert.AreSame (inner, outer.SubTerms ["last"]);
            Assert.AreSame (i3, inner.SubTerms ["first"]);
            Assert.AreSame (i4, inner.SubTerms ["middle"]);
            Assert.AreSame (i5, inner.SubTerms ["last"]);
        }

        [Test]
        public void ShouldReturnOuterIfLastFromInnerIsNotCompositeTerm () {
            var i1 = new IntegerTerm (1);
            var i2 = new IntegerTerm (2);
            var i3 = new IntegerTerm (3);
            var i4 = new IntegerTerm (4);
            var i5 = new IntegerTerm (5);

            CompositeTerm outer = new CompositeTerm ("name");
            outer.Add ("first", i1, false);
            outer.Add ("middle", i2, false);

            outer.Add ("last", i3, false);

            AssociationSwapper swapper = new AssociationSwapper ("first", "last");

            var result = swapper.Swap (outer);

            Assert.AreSame (outer, result);
            Assert.AreSame (i1, outer.SubTerms ["first"]);
            Assert.AreSame (i2, outer.SubTerms ["middle"]);
            Assert.AreSame (i3, outer.SubTerms ["last"]);
        }
    }
}